# 指定文件编码为UTF-8
# coding: utf-8

"""
functions.py 功能说明：
1. 实现神经网络常用的激活函数及其导数
2. 包含常用的损失函数计算
3. 提供数值稳定性的优化实现
4. 支持批量数据处理

包含的主要函数：
- 激活函数：identity、step、sigmoid、ReLU、softmax
- 激活函数导数：sigmoid_grad、relu_grad
- 损失函数：均方误差、交叉熵误差
- 组合函数：softmax_loss(softmax + 交叉熵)

关键点：
- 所有函数都支持NumPy数组运算
- 考虑了数值稳定性(如softmax的溢出处理)
- 交叉熵误差支持one-hot和标签索引两种形式
- 实现了批处理版本的交叉熵误差
"""

# 导入NumPy数值计算库
import numpy as np

def identity_function(x):
    """恒等函数(常用于输出层)"""
    return x

def step_function(x):
    """阶跃函数(返回0或1)"""
    return np.array(x > 0, dtype=np.int)

def sigmoid(x):
    """sigmoid函数(输出范围0-1)"""
    return 1 / (1 + np.exp(-x))

def sigmoid_grad(x):
    """sigmoid函数的导数"""
    return (1.0 - sigmoid(x)) * sigmoid(x)

def relu(x):
    """ReLU函数(Rectified Linear Unit)"""
    return np.maximum(0, x)

def relu_grad(x):
    """ReLU函数的导数"""
    grad = np.zeros(x)
    grad[x>=0] = 1
    return grad

def softmax(x):
    """softmax函数(输出概率分布)

    参数:
        x: 输入向量或矩阵
    返回:
        概率分布(各元素0-1，总和为1)
    """
    if x.ndim == 2:  # 批处理情况
        x = x.T
        x = x - np.max(x, axis=0)  # 防溢出
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T

    # 单个样本情况
    x = x - np.max(x)  # 防溢出
    return np.exp(x) / np.sum(np.exp(x))

def mean_squared_error(y, t):
    """均方误差损失函数"""
    return 0.5 * np.sum((y-t)**2)

def cross_entropy_error(y, t):
    """交叉熵误差损失函数

    参数:
        y: 模型输出(概率分布)
        t: 真实标签(one-hot或类别索引)
    返回:
        交叉熵误差值
    """
    if y.ndim == 1:  # 单个样本转为批处理形式
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    # 如果t是one-hot向量，转换为类别索引
    if t.size == y.size:
        t = t.argmax(axis=1)

    batch_size = y.shape[0]
    # 加1e-7防止log(0)的情况
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

def softmax_loss(X, t):
    """softmax + 交叉熵的组合函数(计算更高效)"""
    y = softmax(X)
    return cross_entropy_error(y, t)

"""
使用说明：
1. 激活函数可直接用于前向传播：
   a = sigmoid(x)
2. 激活函数导数用于反向传播：
   da = sigmoid_grad(a) * dout
3. 损失函数用于评估模型性能：
   loss = cross_entropy_error(y_pred, y_true)
4. softmax_loss组合函数常用于输出层：
   loss = softmax_loss(scores, labels)

注意事项：
1. softmax和交叉熵都有数值稳定性处理
2. 交叉熵误差支持批量计算
3. ReLU及其导数实现高效
"""
